#include <string>
#include <fstream>
#include <filesystem>
#include "data_seq.h"
#include "props.h"

namespace eintik::data::scan {
    FileCache::FileCache()
    {
        for (const auto &entry : std::filesystem::directory_iterator("."))
        {
            if (entry.is_regular_file() && entry.path().extension() == ".bin-scan")
            {
                std::filesystem::remove(entry.path());
            }
        }
    }

    FileCache::~FileCache()
    {
        for (const auto &entry : std::filesystem::directory_iterator("."))
        {
            if (entry.is_regular_file() && entry.path().extension() == ".bin-scan")
            {
                std::filesystem::remove(entry.path());
            }
        }
    }

    void FileCache::register_scan(uint64_t scan)
    {
        // 初始化文件列表，将指定扫描ID的文件列表设置为空
        files[scan] = std::vector<FileInfo>();
    }
    void FileCache::unregister_scan(uint64_t scan)
    {
        files.erase(scan);
    }
    bool FileCache::save_data(uint64_t scan, const std::deque<PosFrame> &dq, double pos_start, double pos_end)
    {
        FileInfo file;
        
        file.pos_start = pos_start;
        file.pos_end = pos_end;
        file.file_name = std::to_string(static_cast<int>(file.pos_start)) + ".bin-scan";

        std::ofstream out(file.file_name, std::ios::binary | std::ios::trunc);
        if (!out)
        {
            return false;
        }
        for (const auto &d : dq)
        {
            out.write(reinterpret_cast<const char*>(d.c.data()), d.c.size() * sizeof(d.c[0]));
            if (out.fail())
            {
                return false;
            }
            out.write(reinterpret_cast<const char*>(&d.t), sizeof(d.t));
            if (out.fail())
            {
                return false;
            }
        }
        files[scan].push_back(file);
        return true;
    }
    bool FileCache::load_data(uint64_t scan, double pos, std::deque<PosFrame> &dq, int cnt_point)
    {
        auto &vfi = files[scan];

        for (auto it = vfi.begin(); it != vfi.end(); ++it)
        {
            auto &file = *it;
            if (!(pos >= file.pos_start && pos <= file.pos_end))
            {
                continue;
            }

            std::ifstream in(file.file_name, std::ios::binary | std::ios::ate);
            if (!in)
            {
                return false;
            }

            size_t size_f = in.tellg();
            in.seekg(0);
            
            auto size_chunk_1 = sizeof(PosFrame::c[0]) * cnt_point;
            auto size_chunk_2 = sizeof(PosFrame::t);
            if (size_f == 0 || size_f % (size_chunk_1 + size_chunk_2) != 0) {
                return false;
            }
            auto cnt_read = size_f / (size_chunk_1 + size_chunk_2);
            
            for (auto i = 0; i < cnt_read; ++i)
            {
                PosFrame pf;
                pf.c.resize(cnt_point);
                in.read(reinterpret_cast<char*>(pf.c.data()), size_chunk_1);
                if (!in || in.gcount() != size_chunk_1)
                {
                    return false;
                }
                in.read(reinterpret_cast<char*>(&pf.t), size_chunk_2);
                if (!in || in.gcount() != size_chunk_2)
                {
                    return false;
                }
                dq.push_back(std::move(pf));
            }
            files[scan].erase(it);
            return true;
        }
        return false;
    }

    FileCache g_file_cache;
    FileCache *file_cache()
    {
        return &g_file_cache;
    }

}